home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
dev
/
gcc
/
ixemul_src.lha
/
ixemul-41.0
/
library
/
__load_seg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-28
|
10KB
|
414 lines
/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* __load_seg.c,v 1.1.1.1 1994/04/04 04:30:54 amiga Exp
*
* __load_seg.c,v
* Revision 1.1.1.1 1994/04/04 04:30:54 amiga
* Initial CVS check in.
*
* Revision 1.5 1992/09/14 01:38:35 mwild
* fix a bug with #! expansion (forgot separating /)
*
* Revision 1.4 1992/08/09 20:37:07 amiga
* change to use 2.x header files by default
*
* Revision 1.3 1992/07/04 19:02:39 mwild
* fix typo, the buffer for interpreter-expansion was ways too small...
*
* Revision 1.2 1992/05/22 01:45:00 mwild
* rewrote interpreter expansion, `should' now work as expected
*
* Revision 1.1 1992/05/14 19:55:40 mwild
* Initial revision
*
*/
#define KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <ctype.h>
#include <string.h>
#if __GNUC__ != 2
#define alloca __builtin_alloca
#endif
/* until sksh is fixed... */
#define BIG_KLUDGE
/* 2.0 support */
#include <utility/tagitem.h>
#include <dos/dostags.h>
extern void *kmalloc (size_t size);
struct my_seg {
BPTR segment; /* the thing our clients can use */
enum { LOADSEG, RESSEG } type;
u_int priv; /* information depending on type */
};
static struct my_seg *try_load_seg (BPTR lock, char *name, char **args);
static inline struct my_seg *
check_resident (char *tmp)
{
struct my_seg *res = 0;
struct Segment *seg = 0;
/* big problem: Commo only stores the bare names in the resident
list. So we have to truncate to the filename part, and so lose
the ability to explicitly load the disk version even if a
resident version is installed */
char *cp = rindex (tmp, '/');
if (cp)
tmp = cp + 1;
else if (cp = index (tmp, ':'))
tmp = cp + 1;
Forbid ();
seg = FindSegment (tmp, 0, 0);
if (seg)
{
/* strange they didn't provide a function for this... */
if (seg->seg_UC >= 0)
seg->seg_UC++;
}
Permit ();
if (seg && (res = (struct my_seg *) kmalloc (sizeof (*res))))
{
res->segment = seg->seg_Seg;
res->type = RESSEG;
res->priv = (u_int) seg;
}
else if (seg)
{
Forbid ();
if (seg->seg_UC > 0)
seg->seg_UC--;
Permit ();
}
return res;
}
static inline struct my_seg *
check_loadseg (char *tmp)
{
struct my_seg *res = 0;
BPTR seg;
seg = LoadSeg (tmp);
if (seg && (res = kmalloc (sizeof (*res))))
{
res->segment = seg;
res->type = LOADSEG;
res->priv = seg;
}
else if (seg)
UnLoadSeg (seg);
return res;
}
void
__free_seg (BPTR *seg)
{
struct my_seg *ms;
ms = (struct my_seg *) seg;
if (ms->type == RESSEG)
{
struct Segment *s = (struct Segment *) ms->priv;
Forbid ();
if (s->seg_UC > 0)
s->seg_UC--;
Permit ();
}
else
UnLoadSeg (ms->priv);
kfree (ms);
}
/*
* This function does what LoadSeg() does, and a little bit more ;-)
* Besides walking the PATH of the user, we try to do interpreter expansion as
* well. But, well, we do it a little bit different then a usual Amiga-shell.
* We check the magic cookies `#!' and `;!', and if found, run the interpreter
* specified on this first line of text. This does *not* depend on any script
* bit set!
* If this check is negative, the script bit is tested. If set, the special
* BPTR (-2) is returned, this is the hint to ssystem() to go and invoke
* system() with the command line. In this case *NO* interpreter expansion
* takes place, as the expansion must have already failed before.
*/
/*
* IMPORTANT: only call this function with all signals masked!!!
*/
/*
* name: the name of the command to load. Can be relative to installed PATH
* args: if set, a string to the first part of an expanded command is stored
*/
BPTR *
__load_seg (char *name, char **args)
{
BPTR lock, parent_lock;
struct my_seg *seg;
char *base_name;
/* perhaps the name is vanilla enough, so that even LoadSeg() groks it? */
if (args) *args = 0;
seg = check_resident (name);
if (! seg)
seg = check_loadseg (name);
if (seg)
return &seg->segment;
/* try to lock the file (using __lock() provides full path-parsing ;-)) */
lock = __lock (name, ACCESS_READ);
if (lock)
{
/* this is tricky.. it is legal to CurrentDir() to a file. This is what
* we do here, we try to LoadSeg("") afterwards ;-)) */
seg = try_load_seg (lock, "", args);
__unlock (lock);
}
/* now we may have a valid segment */
if (seg)
return &seg->segment;
/* if the command was specified with some kind of path, for example with a
* device or a directory in it, we don't run it thru the PATH expander
*/
if (strpbrk (name, ":/"))
return 0;
/* so the command is not directly addressable, but perhaps it's in our PATH? */
{
struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask);
struct CommandLineInterface *cli;
/* but we need a valid CLI then */
if (cli = BTOCPTR (me->pr_CLI))
{
struct path_element {
BPTR next;
BPTR lock;
} *lock_list;
for (lock_list = BTOCPTR (cli->cli_CommandDir);
lock_list;
lock_list = BTOCPTR (lock_list->next))
{
#ifdef 0
KPRINTF(("__load_seg: trying PATH component: next = $%lx, lock = $%lx\n",
lock_list->next, lock_list->lock));
#endif
if (seg = try_load_seg (lock_list->lock, name, args))
break;
}
}
}
if (seg)
return &seg->segment;
errno = ENOENT;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return 0;
}
static struct my_seg *
try_load_seg (BPTR lock, char *name, char **args)
{
BPTR ocd;
struct my_seg *seg;
if (args) *args = 0;
ocd = CurrentDir (lock);
seg = check_loadseg (name);
/* try to do interpreter - expansion, but only if args is non-zero */
if (! seg && args)
{
int fd;
char magic[2];
struct stat stb;
if (syscall (SYS_stat, name, &stb) == 0 && S_ISREG (stb.st_mode))
{
if ((fd = syscall (SYS_open, name, 0)) >= 0)
{
if (syscall (SYS_read, fd, magic, 2) == 2 &&
(((magic[0] == '#' || magic[0] == ';') && magic[1] == '!')
#ifdef BIG_KLUDGE
/* FIXME !!! */
/* I can't currently use #! expansion with sksh, since the shell
* does the same expansion again, and then doesn't seem to get
* it right anymore... this is the so far unused hidden bit,
* set it with PROTECT +h
*/
|| (stb.st_amode & (1 << 7))
#endif
))
{
char interp[MAXPATHLEN + 1], *interp_start;
int n;
if ((n = syscall (SYS_read, fd, interp, MAXINTERP)) > 0)
{
char *cp, *colon, ch;
char *interp_path;
#ifdef BIG_KLUDGE
/* FIXME */
if (stb.st_amode & (1<<7))
{
strcpy (interp, "sksh -c");
n = strlen (interp);
}
#endif
/* oky.. got one.. terminate with 0 and try to find end of it */
interp[n] = 0;
for (interp_start = interp; isspace(*interp_start) && interp_start < interp + n; interp_start++);
for (cp = interp_start; cp < interp + n; cp++)
if (*cp == 0 || isspace (*cp)) break;
ch = *cp;
*cp = 0;
/* okay, lets try to load this instead. Call us recursively,
* but leave out the argument-argument, so we can't get
* into infinite recursion. Interpreter-Expansion is only
* done the first time __load_seg() is called from
* ssystem()
*/
seg = (struct my_seg *) __load_seg (interp_start, 0);
*cp = ch;
if (! seg)
goto ret;
/* in this case, set the argument as well.
*/
/* first skip intergap whitespace */
for (;cp < interp + n; cp++)
if (!*cp || ! isspace (*cp) || *cp == '\n')
break;
if (*cp && *cp != '\n')
{
/* we read a certain amount of bytes, but we
* unconditionally stop when we hit newline
*/
interp_path = cp;
/* crop any further arguments, only ONE argument
* is supported
*/
for (;cp < interp + n; cp++)
if (isspace (*cp))
break;
if (cp < interp + n)
*cp = 0;
*cp++ = ' ';
}
else
cp = interp_path = interp_start;
#ifdef BIG_KLUDGE
/* FIXME */
if (stb.st_amode & (1<<7))
{
*cp++ = '\"';
}
#endif
if (ix.ix_translate_slash && name[0] != '/')
*cp++ = '/';
if (name[0] != '/' && !index (name, ':'))
{
if (NameFromLock (lock, cp,
MAXPATHLEN-(cp-interp)) == -1)
{
if (*name)
strcat (strcat (cp, "/"), name);
}
else
strcpy (cp, name);
}
else
strcpy (cp, name);
if (ix.ix_translate_slash && (colon = index (cp, ':')))
*colon = '/';
*args = (char *) syscall (SYS_strdup, interp_path);
#ifdef BIG_KLUDGE
/* FIXME */
if (stb.st_amode & (1<<7))
{
/* tell ssystem() that it should add the closing
* quote... shudder.. I want a newer sksh !
*/
*args = (char *)(-(int)*args);
}
#endif
}
}
syscall (SYS_close, fd);
}
ret:
/* check to see if script bit is set, no matter whether we could
* actually open the file or not. If set, set seg to magic BPTR */
if (! seg && (stb.st_amode & FIBF_SCRIPT))
seg = (struct my_seg *) -2;
}
}
CurrentDir (ocd);
return seg;
}